/*
 *  SPAGL Copyright (C) 2008 Sam Pottinger
 *  This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser 
 *  General Public License as published by the Free Software Foundation; either version 2.1 of the License, or 
 *  (at your option) any later version. This library is distributed in the hope that it will be useful, but 
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *  See the GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License along with this library; if not, 
 *  write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 */

package spagswt;

import net.miginfocom.swt.*;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;

import spagcore.*;

/**
 * A Shell (org.eclipse.swt.widgets.Shell) that conforms to the SpaglCoreWindow interface
 * @author Sam Pottinger
 */
public class SpaglWindow implements SpaglCoreWindow, SpaglSwtContainer, SpaglSwtWidget{

	// Searialize
	private static final long serialVersionUID = 1L;
	public static final int DO_NOTHING_ON_CLOSE = 0;
	public static final int HIDE_ON_CLOSE = 1;
	public static final int DISPOSE_ON_CLOSE = 2;
	public static final int EXIT_ON_CLOSE = 3;
	
	private SpaglCoreApp parentApp;
	private MigLayout layoutManager;
	private int defaultCloseOperation;
	private Shell windowShell;
	
	/**
	 * The bare-bones constructor for a window
	 * @param newApp The application that this window will belong to
	 * @param title The title to be displayed at the top of this window
	 * @param newLayoutManager The layout manager to be used in this window
	 */
	public SpaglWindow(SpaglCoreApp newApp, String title, MigLayout newLayoutManager)
	{
		windowShell = new Shell();
		windowShell.setText(title);
		layoutManager = newLayoutManager;
		parentApp = newApp;
		defaultCloseOperation = DISPOSE_ON_CLOSE;
		this.setLayoutManager(newLayoutManager);
		parentApp.addWindow(this);
	}
	
	/**
	 * Creates a new window with a default layout manager (MigLayout)
	 * @param newApp The application that this window will belong to
	 * @param title The title to be displayed at the top of this window
	 */
	public SpaglWindow(SpaglCoreApp newApp, String title)
	{
		windowShell = new Shell();
		windowShell.setText(title);
		layoutManager = new MigLayout();
		parentApp = newApp;
		this.setCloseOperation(DISPOSE_ON_CLOSE);
		this.setLayoutManager(new MigLayout("fillx", "[left]rel[grow,fill]", "[]10[]"));
		parentApp.addWindow(this);
	}
	
	/**
	 * Creates a new window as a child of another window
	 * @param newApp The application that this window will belong to
	 * @param title The title to be displayed at the top of this window
	 * @param newLayoutManager The layout manager to be used in this window
	 * @param parent The window that this will be a child of
	 */
	public SpaglWindow(SpaglCoreApp newApp, String title, MigLayout newLayoutManager, SpaglCoreWindow parent)
	{
		windowShell = new Shell(((SpaglWindow)parent).getShell());
		windowShell.setText(title);
		layoutManager = newLayoutManager;
		parentApp = newApp;
		defaultCloseOperation = DISPOSE_ON_CLOSE;
		this.setLayoutManager(newLayoutManager);
		parentApp.addWindow(this);
	}
	
	/**
	 * Creates a new window as a child of another window with the default layout manager (MigLayout)
	 * @param newApp The application that this window will belong to
	 * @param title The title to be displayed at the top of this window
	 * @param parent The window that this will be a child of
	 */
	public SpaglWindow(SpaglCoreApp newApp, String title, SpaglCoreWindow parent)
	{
		windowShell = new Shell(((SpaglWindow)parent).getShell());
		windowShell.setText(title);
		layoutManager = new MigLayout();
		parentApp = newApp;
		this.setCloseOperation(DISPOSE_ON_CLOSE);
		this.setLayoutManager(new MigLayout("fillx", "[left]rel[grow,fill]", "[]10[]"));
		parentApp.addWindow(this);
	}
	
	/**
	 * Sets the layout to be used in this window
	 * @param layout A MigLayout object to be used as the layout manager
	 */
	public void setLayoutManager(MigLayout layout)
	{
		windowShell.setLayout(layout);
		layoutManager = layout;
	}

	@SuppressWarnings("deprecation")
	/**
	 * Preform the close event/code
	 */
	public void close() {
		switch(defaultCloseOperation) {
			case DO_NOTHING_ON_CLOSE: return;
			case HIDE_ON_CLOSE: windowShell.setVisible(false); break;
			case DISPOSE_ON_CLOSE: windowShell.dispose(); break;
			case EXIT_ON_CLOSE: System.exit(0); break;
		}
		
	}

	/**
	 * Gets the actions that will be taken when this window is closed
	 * @return The integer representation of the close operation
	 */
	public int getCloseOperation() {
		
		return defaultCloseOperation;
	}

	/**
	 * Determines how the window will close
	 * @param newOperation The string representation of the desired close operation
	 */
	public void setCloseOperation(String newOperation) {
		if(newOperation.equals(NOTHING)) this.setCloseOperation(DO_NOTHING_ON_CLOSE);
		else if (newOperation.equals(HIDE)) this.setCloseOperation(HIDE_ON_CLOSE);
		else if (newOperation.equals(DISPOSE)) this.setCloseOperation(DISPOSE_ON_CLOSE);
		else if (newOperation.equals(EXIT)) this.setCloseOperation(EXIT_ON_CLOSE);
		else throw new java.lang.IllegalArgumentException();
	}
	
	/**
	 * Determines how the window will close
	 * @param newOperation The integer representation of the desired close operation
	 */
	public void setCloseOperation(int newOperation)
	{
		defaultCloseOperation = newOperation;
	}

	/**
	 * Prepares the window and shows it to the user
	 */
	public void display() {
		windowShell.pack();
		windowShell.setVisible(true);
	}
	
	/**
	 * Gets the layout manager attached to this window
	 * @return The library-specific MigLayout manager attached to this object
	 */
	public MigLayout getLayoutManager()
	{
		return layoutManager;
	}

	/**
	 * Places a widget on this container with the given string parameters
	 * @param targetWidget the target widget to be placed in this container
	 * @param parameters the string parameters for the layout manager
	 */
	public void placeWidget(SpaglCoreWidget targetWidget, String parameters) {
		
		((SpaglSwtWidget)targetWidget).getNativeWidget().setLayoutData(parameters);
		
	}
	
	/**
	 * Places a widget on this container with the given string parameters
	 * @param targetWidget the target widget to be placed in this container
	 * @param parameters the string parameters for the layout manager
	 */
	public void placeWidget(Control targetWidget, String parameters)
	{
		targetWidget.setLayoutData(parameters);
	}
	
	/**
	 * Gets the parent SpaglApp that this window belongs to
	 * @return The SpaglApp that this window belongs to as a SpaglCoreApp
	 */
	public SpaglCoreApp getApp()
	{
		return parentApp;
	}

	/**
	 * Binds an event to to a method so that when the event is fired the method is called
	 * @param eventID the integer (int) id of the event to be bound <br>(string constant ACTIVATED_EVENT, WINDOW_CLOSING_EVENT, DEACTIVATED_EVENT, WINDOW_RESTORED_EVENT, or WINDOW_MINIMIZED_EVENT)
	 * @param method The name of the method to be called when the event is fired
	 * @param o The object where the method is to be invoked
	 */
	public void addEventListener(int eventID, String method, Object o) {
		try{
			switch(eventID)
			{
				case SpaglCoreEvent.ACTIVATED_EVENT: windowShell.addListener(SpaglEvent.ACTIVATED_EVENT, new SpaglEventListener(o.getClass().getMethod(method, SpaglCoreEvent.class), o, SpaglEvent.ACTIVATED_EVENT));
				case SpaglCoreEvent.WINDOW_CLOSING_EVENT: windowShell.addListener(SpaglEvent.WINDOW_CLOSING_EVENT, new SpaglEventListener(o.getClass().getMethod(method, SpaglCoreEvent.class), o, SpaglEvent.WINDOW_CLOSING_EVENT));
				case SpaglCoreEvent.DEACTIVATED_EVENT: windowShell.addListener(SpaglEvent.DEACTIVATED_EVENT, new SpaglEventListener(o.getClass().getMethod(method, SpaglCoreEvent.class), o, SpaglEvent.DEACTIVATED_EVENT));
				case SpaglCoreEvent.WINDOW_RESTORED_EVENT: windowShell.addListener(SpaglEvent.WINDOW_RESTORED_EVENT, new SpaglEventListener(o.getClass().getMethod(method, SpaglCoreEvent.class), o, SpaglEvent.WINDOW_RESTORED_EVENT));
				case SpaglCoreEvent.WINDOW_MINIMIZED_EVENT: windowShell.addListener(SpaglEvent.WINDOW_MINIMIZED_EVENT, new SpaglEventListener(o.getClass().getMethod(method, SpaglCoreEvent.class), o, SpaglEvent.WINDOW_MINIMIZED_EVENT));
				default: throw new IllegalArgumentException("Event not supported by this widget");
			}}
		catch (SecurityException e) {e.printStackTrace();} 
		catch (NoSuchMethodException e) {e.printStackTrace();}
		
	}

	/**
	 * Gets the height in pixels of this widget
	 * 
	 * @return The vertical size of this widget
	 */
	public int getHeight() {
		return windowShell.getSize().y;
	}

	/**
	 * Gets the title being displayed at the top of this window
	 * @return The string being displayed at the top of this window
	 */
	public String getTitle() {
		return windowShell.getText();
	}

	/**
	 * Gets the width in pixels of this widget
	 * 
	 * @return The horizontal size of this widget
	 */
	public int getWidth() {
		return windowShell.getSize().x;
	}

	/**
	 * Sets the title to be displayed at the top of this window
	 * @param t The new string title to be displayed
	 */
	public void setTitle(String t) {
		windowShell.setText(t);
	}

	/**
	 * Disposes this window through SWT
	 */
	public void dispose() {
		windowShell.dispose();
	}

	/**
	 * Resizes the window to fit the widgets it holds
	 */
	public void pack() {
		windowShell.pack();
	}

	/**
	 * Sets the size of the object in pixels
	 * 
	 * @param xSize the horizontal size in size x
	 * @param ySize the vertical size in size y
	 */
	public void setSize(int xSize, int ySize) {
		windowShell.setSize(xSize, ySize);
	}

	/**
	 * Sets if this window can be seen by the user
	 * @param v True to specify that this window is visible or false to specify that it is not
	 */
	public void setVisible(boolean v) {
		windowShell.setVisible(v);
	}
	
	/**
	 * Gets this widget as a native SWT Shell (org.eclipse.swt.widgets.Shell)
	 * @return A SWT Shell object
	 */
	public Shell getShell()
	{
		return windowShell;
	}

	/**
	 * Gets the native SWT Composite (org.eclipse.swt.widgets.Composite) for this widget 
	 * @return A SWT Composite object
	 */
	public Composite getComposite() {
		return (Composite)windowShell;
	}

	/**
	 * Gets this widget as a native SWT Shell (org.eclipse.swt.widgets.Shell)
	 * @return A SWT Shell object
	 */
	public Shell getNativeWidget() {
		return this.getShell();
	}

	/**
	 * Gets the container for this object (in this case it is just itself)
	 * @return this
	 */
	public SpaglCoreContainer getContainer() {
		return this;
	}

}
